package com.xlongwei.accounts.controller;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Get;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Param;
import org.noear.solon.annotation.Post;
import org.noear.solon.core.handle.Result;
import org.noear.solon.validation.annotation.Min;
import org.noear.solon.validation.annotation.NotBlank;
import org.noear.solon.validation.annotation.NotNull;
import org.noear.solon.validation.annotation.Pattern;
import org.noear.solon.validation.annotation.Valid;

import com.xlongwei.accounts.dao.AccountDao;
import com.xlongwei.accounts.model.Account;
import com.xlongwei.accounts.service.AccountService;
import com.xlongwei.accounts.service.RecordService;
import com.xlongwei.accounts.view.Daily;
import com.xlongwei.accounts.view.Daily.Row;
import com.xlongwei.accounts.view.Query;

import cn.dev33.satoken.annotation.SaCheckLogin;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Valid
@Controller
@SaCheckLogin
@Mapping("account")
public class AccountController {
    @Inject
    AccountDao accountDao;
    @Inject
    AccountService accountService;
    @Inject
    RecordService recordService;
    @Inject
    RecordController recordController;

    @Get
    @Post
    @Mapping("list")
    public Result<?> list(boolean withBalance, boolean hiddenZero, Integer partnerid, LocalDate end) {
        Integer userid = UserController.userid();
        if (partnerid != null && partnerid > 0 && recordController.isPartner(userid, partnerid)) {
            userid = partnerid;
        }
        List<Account> list = accountDao.list(userid);
        if (withBalance) {
            // if(end == null) end = LocalDate.now();
            Map<Integer, Long> balances = accountService.balances(userid, end);
            for (Account account : list) {
                Long balance = balances.get(account.getAccountid());
                if (balance != null) {
                    account.setBalance(RecordController.yuan(balance.intValue()));
                } else {
                    account.setBalance("0");
                }
            }
            if(end == null) end = LocalDate.now();
            for (Account account : list) {
                if (!"2".equals(account.getType())) {
                    continue;
                }
                int[] days = AccountService.billRepayDay(account.getName());
                if (days[0] < 1 || days[0] > 31 || days[1] > 31) {
                    continue;
                }
                int dayOfMonth = end.getDayOfMonth();// 2/27 2<day<27 16/9 not(9<day<16)
                boolean showBill = days[1] < 1 || (days[0] < days[1] && days[0] < dayOfMonth && dayOfMonth <= days[1])
                        || (days[0] > days[1] && (days[0] < dayOfMonth || dayOfMonth <= days[1]));
                log.debug("credit card {}={} bill day {} repay day {} show bill {}={}", account.getAccountid(),
                        account.getName(), days[0], days[1], dayOfMonth, showBill);
                if (showBill) {
                    String creditbill = accountService.creditbill(account.getAccountid(), days, end);
                    account.setCreditbill(creditbill);
                } else {
                    account.setCreditbill(null);
                }
            }
            if (hiddenZero) {
                list = list.stream()
                        .filter(item -> !"0".equals(item.getBalance())
                                || ("2".equals(item.getType()) && !"0".equals(item.getCreditbill())))
                        .collect(Collectors.toList());
            }
        }
        return Result.succeed(list);
    }

    @Post
    @Mapping("create")
    public Result<?> create(@Param(defaultValue = "1") @Pattern("[1-4]") String type,
            @NotBlank @Pattern(UserController.PATTERN_NAME) String name) {
        Integer userid = UserController.userid();
        List<Account> list = accountDao.list(userid);
        for (Account account : list) {
            if (name.equals(account.getName())) {
                return Result.failure("名称重复");
            }
        }
        Account account = new Account();
        account.setType(type);
        account.setUserid(userid);
        account.setName(name);
        Integer accountid = accountDao.create(account);
        account.setAccountid(accountid);
        log.info("userid={} create accountid={} type={} name={}", userid, accountid, type, name);
        return Result.succeed(account);
    }

    @Post
    @Mapping("update")
    public Result<?> update(@NotNull @Min(1) Integer accountid,
            @NotBlank @Pattern(UserController.PATTERN_NAME) String newName) {
        Integer userid = UserController.userid();
        Account account = accountDao.retrieve(accountid);
        if (account != null && userid.equals(account.getUserid())
                && !newName.equals(account.getName())) {
            log.info("userid={} update accountid={} oldName={} newName={}", userid, accountid,
                    account.getName(), newName);
            account.setName(newName);
            accountDao.update(account);
        }
        return Result.succeed(account);
    }

    @Get
    @Post
    @Mapping("history")
    public Result<?> history(@NotNull @Min(1) Integer accountid, boolean withRemark, LocalDate end, Integer limit) {
        Integer userid = UserController.userid();
        Query query = new Query();
        query.setUserid(userid);
        query.setAccountid(accountid);
        query.setWithRemark(withRemark);
        query.setWithoutTransfer(false);
        List<Daily> list = recordService.list(query);
        int fen = 0;
        for (int i = list.size() - 1; i >= 0; i--) {
            Daily daily = list.get(i);
            List<Row> records = daily.getRecords();
            for (int j = records.size() - 1; j >= 0; j--) {
                Row record = records.get(j);
                if (record.getAccountid_in() == accountid) {
                    fen += record.getFen();
                } else {
                    fen -= record.getFen();
                }
                record.setBalance(RecordController.yuan(fen));
            }
            daily.setBalance(RecordController.yuan(fen));
        }
        boolean isLimit = limit !=null && limit > 0;
        if(isLimit && list.isEmpty() == false) {
            int fromIndex = 0, toIndex = list.size(), toRecords = 0;
            if(end != null) {
                fromIndex = IntStream.range(0, list.size()).filter(i -> list.get(i).getDay().compareTo(end.toString())<=0).findFirst().orElse(-1);
                if(fromIndex == -1) return Result.succeed();
            }
            for(int i= fromIndex; i < list.size(); i++) {
                Daily daily = list.get(i);
                toRecords += daily.getRecords().size();
                if(toRecords >= limit) {
                    toIndex = i + 1;
                    break;
                }
            }
            return Result.succeed(list.subList(fromIndex, toIndex));
        }
        return Result.succeed(list);
    }
}
